// $URL: http://mingw-lib.googlecode.com/svn/trunk/working/avcodec_to_widget_8/t_generator.cpp $
// $Rev: 292 $
// $Author: akio.miyoshi $
// $Date:: 2010-07-28 03:50:10 +0000#$

#include "t_generator.h"
#include "t_box_player.h"

void T_Generator::breakTimer()
{
    m_base_msecs = -1;
    m_base_bytes = 0;
}

qint64 T_Generator::elapsed()
{
    QAudioOutput *v_output = m_player_ctx->m_audioOutput;
    QAudioFormat v_format = v_output->format();
    qint64 v_bytesWaiting = (v_output->bufferSize() - v_output->bytesFree());
    if(v_bytesWaiting == 0)
    {
        return -1;
    }
    if(m_base_msecs < 0)
    {
        return -1;
    }
    qint64 v_bytesPlayed = m_out_read_size - v_bytesWaiting;
    qint64 v_msecsDelta =
            ((qint64)1000)
            * (v_bytesPlayed - m_base_bytes)
            / ( v_format.channels() * v_format.sampleSize() / 8 )
            / v_format.frequency();
    qint64 v_msecs = m_base_msecs + v_msecsDelta;
    return v_msecs;
}

// In qaudiooutput_win32_p.cpp
// QAudioOutputPrivate::deviceReady() seek() backwards
// (when part of the final read() data could not be written to the sound device)
// Generator::m_audio_last_read (=QByteArray) holds final read() data to handle
// this case.
bool T_Generator::seek(qint64 pos)
{
    qint64 v_curr_pos = this->pos();
    qint64 v_seek_len = v_curr_pos - pos;
    qDebug() << "[Generator::seek()]" << v_seek_len << m_audio_last_read.size();
    if(v_seek_len <= 0)
    {
        qDebug() << "=====>seek() error (1)";
        return false;
    }
    m_max_seek_size = qMax(m_max_seek_size, v_seek_len);
    if(v_seek_len > m_audio_last_read.size())
    {
        qDebug() << "=====>seek() error (2)";
        m_out_read_size -= m_audio_last_read.size();
        m_audio_data_left.prepend(m_audio_last_read);
        m_audio_data_left.clear();
        return false;
    }
    m_out_read_size -= v_seek_len;
    m_audio_data_left.prepend(p_pop_back(m_audio_last_read, v_seek_len));
    qDebug() << "=====>seek() ok";
    return true;
}

qint64 T_Generator::readData(char *data, qint64 len)
{
    //qDebug() << "[Generator::readData()]" << "[this->pos()]" << this->pos() << "[len]" << len;
    Q_ASSERT(len%2==0);
    //[m_max_seek_size]
    m_max_seek_size = qMax(m_max_seek_size, len);
    //[left_len, read_len]
    qint64 prec_len = 0;
    qint64 need_len = len;
    //[pop from m_audio_data_left]
    QByteArray v_result = p_pop_front(m_audio_data_left, need_len);
    need_len -= v_result.size();
    prec_len += v_result.size();
    //[decode packet if needed]
    if(need_len>0)
    {
        QByteArray v_packet_bytes = p_readPacket(prec_len, need_len);
        need_len -= v_packet_bytes.size();
        prec_len += v_packet_bytes.size();
        v_result.append(v_packet_bytes);
    }
    //qDebug() << "[Generator::readData()]" << read_len << v_result.size();
    Q_ASSERT(prec_len==v_result.size());
    //[save bytes beyond capacity => m_audio_data_left]
    if(v_result.size() > len)
    {
        m_audio_data_left.append(p_pop_back(v_result, v_result.size()-len));
    }
    //[append the result bytes => m_audio_last_read (prepare for possible seek()-ing backwards)]
    m_audio_last_read.append(v_result);
    //[reduce m_audio_last_read's size => m_max_seek_size]
    if(m_audio_last_read.size() > m_max_seek_size)
    {
        m_audio_last_read = m_audio_last_read.right(m_max_seek_size);
    }
    //Q_ASSERT(v_result.size()<=len);
    //qDebug() << "[Generator::readData()]" << len << v_result.size();
    memcpy(data, v_result.constData(), v_result.size());
    m_out_read_size += v_result.size();
    return v_result.size();
}

QByteArray T_Generator::p_readPacket(qint64 prec_len, qint64 need_len)
{
    //[seek lock]
    QReadWriteLock *v_seek_mutex = m_player_ctx->seekMutex();
    if(!v_seek_mutex->tryLockForRead(100))
    {
        qDebug() << "[T_Generator::p_readPacket()]: (!v_queue_lock->tryLock(100))";
        return QByteArray();
    }
    QReadLocker v_seek_locker(v_seek_mutex);
    Q_UNUSED(v_seek_locker);
    v_seek_mutex->unlock();
    //
    if(!m_player_ctx->m_stopwatch.isActive())
    {
        return QByteArray();
    }
    //
    if(m_player_ctx->m_audio.packet_queue.size()>0 && m_player_ctx->m_audio.packet_queue.head()->isNull())
    {
        //m_player_ctx->m_audio.packet_queue.dequeue();
        return QByteArray();
    }
    //[left_len, read_len]
    qint64 read_len = 0;
    QByteArray v_result;
    if(need_len>0 && m_player_ctx->m_audio.packet_queue.size()>0)
    {
        T_AV_Packet *v_head_packet = m_player_ctx->m_audio.packet_queue.head();
        m_base_bytes = m_out_read_size + prec_len;
        m_base_msecs = v_head_packet->timing();
    }
    while(need_len>0 && m_player_ctx->m_audio.packet_queue.size()>0)
    {
        T_AV_Packet *v_head_packet = m_player_ctx->m_audio.packet_queue.head();
        QByteArray v_audio_byes = v_head_packet->decodeAudio();
        need_len -= v_audio_byes.size();
        read_len += v_audio_byes.size();
        v_result.append(v_audio_byes);
        delete m_player_ctx->m_audio.packet_queue.dequeue();
    }
    //qDebug() << "[Generator::p_readPacket()]" << "read_len" << v_result.size();
    Q_ASSERT(read_len==v_result.size());
    // v_result.size() might exceed wanted_len.
    return v_result;
}

QByteArray T_Generator::p_pop_front(QByteArray &a_bytes, int a_maxlen)
{
    int v_len = qMin(a_maxlen, a_bytes.size());
    QByteArray v_pop = a_bytes.left(v_len);
    a_bytes = a_bytes.right(a_bytes.size()-v_len);
    return v_pop;
}

QByteArray T_Generator::p_pop_back(QByteArray &a_bytes, int a_maxlen)
{
    int v_len = qMin(a_maxlen, a_bytes.size());
    QByteArray v_pop = a_bytes.right(v_len);
    a_bytes = a_bytes.left(a_bytes.size()-v_len);
    return v_pop;
}
